﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Luna;
using Luna.Framework;
using VulnDBExplorer.Framework.Impl;
using Luna.Framework.Manifest;
using WeifenLuo.WinFormsUI.Docking;
using VulnDBExplorer.Services;

namespace VulnDBExplorer.Forms {
	public partial class MainForm : Form, IActionManager, IViewManager, IApplication {

		class WorkingSet : IActionableWorkingSet {

			private List<IActionable> actions = new List<IActionable>();

			public int PendingActionCount {
				get {
					lock (actions)
						return actions.Count;
				}
			}

			public IEnumerable<IActionable> WorkingActions {
				get { return actions; }
			}

			public void addAction(IActionable actionable) {
				lock (actions)
					actions.Add(actionable);
			}

			public void removeAction(IActionable actionable) {
				lock (actions)
					actions.Remove(actionable);
			}

			internal void abortAll() {
				lock (actions)
					foreach (IActionable action in actions)
						action.abort(null);
			}

			public int WorkingActionAcount { get { return actions.Count; } }
		}

		private IAppContext context;
		private IList<IView> views;
		private WorkingSet workset;

		public MainForm() {
			InitializeComponent();
			Actions = new List<IActionable>();
			workset = new WorkingSet();
		}

		public IAppContext Context {
			get { return context; }
			set {
				if (context == null) {
					context = value.createChildContext(Name);
					context.Host = this;
					context.addService(this); // register itself as an service in its context.
					populateActions();
				}
			} 
		}

		#region IActionManager

		public IList<IActionable> Actions {
			get;
			set;
		}

		IActionableWorkingSet IActionManager.WorkingSet {
			get { return workset; }
		}
	
		#endregion

		#region IViewManager members

		public IList<IView> Views {
			get { return views != null ? views : (views = new List<IView>()); }
		}

		public IView getView(string viewName) {
			return views.FirstOrDefault(v => v.Name.Equals(viewName));
		}

		public void showView(IView view) {
			//dockPanel1.SendToBack();
			showView(view, null);
		}


		public void showView(IView view, IViewLayoutData layoutData) {
			Control ctrl = view.getViewControl(Context, null);
			if (ctrl is DockContent)
				(ctrl as DockContent).Show(dockPanel1);
		}

		public DialogResult showForm(Form f, bool modalDialog) {
			if (InvokeRequired)
				return (DialogResult)Invoke(new Func<Form, bool, DialogResult>(showForm), f, modalDialog);
			else {
				if (modalDialog)
					return f.ShowDialog();
				else {
					f.Show();
					return DialogResult.OK;
				}
			}

		}

		#endregion

		public IProgressMonitor createProgressMonitor(IProgressMonitor parentTask) {
			if (InvokeRequired)
				return (IProgressMonitor)Invoke(new Func<IProgressMonitor, IProgressMonitor>(createProgressMonitor), parentTask);
			else {
				if (ProgressForm.Instance == null)
					new ProgressForm(Context);
				ProgressForm.Instance.Show();
				return ProgressForm.Instance.createTaskMonitor(parentTask);
			}
		}

		IProgressMonitor IApplication.createProgressMonitor() {
			return (this as IApplication).createProgressMonitor(null);
		}

		private void populateActions() {
			Actions.Add(new MainFormAction("FileExit", "&Exit", (o, e) => this.Close()));
			Actions.Add(new MainFormAction("ShowView", "", (o, e) => showMDIChild(o,e)));
		}

		protected override void OnClosing(CancelEventArgs e) {
			if (workset.PendingActionCount > 0) {
				if (MessageBox.Show("There are {0} task(s) pending. Do you want to exit?".format(workset.WorkingActionAcount),
					null, MessageBoxButtons.YesNo) != System.Windows.Forms.DialogResult.Yes) {
					e.Cancel = true;
					return;
				}
				workset.abortAll();
			}
			base.OnClosing(e);
		}

		protected void showMDIChild(object target, EventArgs args) {
			if (args is ActionExecutionArgs) {
				ActionExecutionArgs arg = args as ActionExecutionArgs;
				if (arg.Data is IManifest) {
					IManifest manifest = arg.Data as IManifest;
					string formName = manifest.getProperty("view-name", "");
					if (formName.isNotNullAndEmpty()) {
						IView formView = getView(formName);
						showView(formView);
					}
				}
			}
		}

		DialogResult IApplication.showForm(Form f, bool modal) {
			if (modal)
				return f.ShowDialog();
			f.Show();
			return DialogResult.OK;
		}

	}

	public class MainFormAction : VisualActionable {

		public MainFormAction(string name, string text, EventHandler<ActionExecutionArgs> executor) {
			this.Name = name;
			this.Text = text;
			this.Execute += executor;
		}
	}
}
